#include "../lib_include/PollPoller.h"
#include "../lib_include/Logger.h"
#include "../lib_include/Types.h"
#include "../lib_include/Channel.h"

#include <assert.h>
#include <errno.h>
#include <poll.h>

using namespace netlib;
using namespace netlib::net;

PollPoller::PollPoller(EventLoop* loop) : Poller(loop)
{ }

PollPoller::~PollPoller() = default;

// 系统调用poll
Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels)
{
    int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs);
    int savedErrno = errno;
    Timestamp now(Timestamp::now()); // 记录当前时间
    if (numEvents > 0) // 有事件就绪
    {
        LOG_TRACE << numEvents << " events happened";
        fillActiveChannels(numEvents, activeChannels); // 有就绪事件则加入到活动通道列表
    }
    else if (numEvents == 0) // 没有事件就绪
    {
        LOG_TRACE << " nothing happened";
    }
    else // 出现错误
    {
        if (savedErrno != EINTR)
        {
            errno = savedErrno;
            LOG_SYSERR << "PollPoller::poll()";
        }
    }
    return now; // 返回当前时间
}

// 将有就绪事件的通道添加到活动通道列表
void PollPoller::fillActiveChannels(int numEvents,
                                    ChannelList* activeChannels) const
{
    for (PollFdList::const_iterator pfd = pollfds_.begin();
        pfd != pollfds_.end() && numEvents > 0; ++pfd)
    {
        if (pfd->revents > 0)
        {
            --numEvents;
            ChannelMap::const_iterator ch = channels_.find(pfd->fd);
            assert(ch != channels_.end());
            Channel* channel = ch->second;
            assert(channel->fd() == pfd->fd);
            channel->set_revents(pfd->revents);
            activeChannels->push_back(channel);
        }
    }
}

void PollPoller::updateChannel(Channel* channel)
{
    Poller::assertInLoopThread();
    LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events();
    if (channel->index() < 0) // < 0 channel是一个新的通道
    {
        assert(channels_.find(channel->fd()) == channels_.end());
        struct pollfd pfd;
        pfd.fd = channel->fd();
        pfd.events = static_cast<short>(channel->events());
        pfd.revents = 0;
        pollfds_.push_back(pfd); // 将新的描述符尾插到pollfd数组的尾端
        int idx = static_cast<int>(pollfds_.size())-1;
        channel->set_index(idx);
        channels_[pfd.fd] = channel; // 将fd与Channel，插入poll监听表
    }
    else // > 0 之前注册过
    {
        // update existing one
        assert(channels_.find(channel->fd()) != channels_.end());
        assert(channels_[channel->fd()] == channel);
        int idx = channel->index();
        assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));
        struct pollfd& pfd = pollfds_[idx];
        assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1);
        pfd.fd = channel->fd();
        pfd.events = static_cast<short>(channel->events());
        pfd.revents = 0;
        if (channel->isNoneEvent()) // 标识暂时不监听这个fd，却不从监听表中取出，-1防止fd=0
            pfd.fd = -channel->fd()-1; // 使其为负数
    }
}

void PollPoller::removeChannel(Channel* channel) // 从监听表中移除channel
{
    Poller::assertInLoopThread(); // 断言是否为创建者线程调用
    LOG_TRACE << "fd = " << channel->fd();
    assert(channels_.find(channel->fd()) != channels_.end());
    assert(channels_[channel->fd()] == channel);
    assert(channel->isNoneEvent()); // 删除前先清零监听事件
    int idx = channel->index();
    assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));
    const struct pollfd& pfd = pollfds_[idx]; (void)pfd;
    assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events());
    size_t n = channels_.erase(channel->fd()); // 从监听表中删除
    assert(n == 1); (void)n;

    // 如果是pollfd数组的最后一个则直接删除
    if (implicit_cast<size_t>(idx) == pollfds_.size()-1)
        pollfds_.pop_back();
    else // 先与数组中最后一个替换，然后尾删
    {
        int channelAtEnd = pollfds_.back().fd;
        iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); // 与最后一个互换
        if (channelAtEnd < 0)
            channelAtEnd = -channelAtEnd-1;

         // 重新设置最后一个通道对象中在pollfd数组的位置
        channels_[channelAtEnd]->set_index(idx);
        pollfds_.pop_back();
    }
}

